using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.IO;
using System.IO.Ports;
using System.Xml.Serialization;
using Waymex.Diagnostics;
//using Waymex.IO.Serial;
using System.Globalization;

namespace Waymex.Gps.Nmea
{
    internal class SerialLink : IDisposable 
	{
        private SerialPort m_commPort = new SerialPort();

        private const string NMEA_START = "$";
		private const int RX_QUEUE = 1024;
		
		private int m_port = 1;
		private int m_baud = 4800;
        private bool disposed;
		private StringBuilder m_sbSentence = new StringBuilder();

        internal SerialLink()
        {
            //m_commPort.DataReceived += new SerialDataReceivedEventHandler(object obj, SerialErrorReceivedEventArgs args);
            m_commPort.DataReceived+=new SerialDataReceivedEventHandler(m_commPort_DataReceived);
        }
        internal void Open()
        {
            m_commPort.BaudRate = m_baud;
            m_commPort.PortName = String.Concat("COM", m_port.ToString(CultureInfo.InvariantCulture));
            m_commPort.Parity = Parity.None;
            m_commPort.StopBits = StopBits.One;
            m_commPort.Open();

        }
        internal void Close()
        {
            m_commPort.Close();
        }
        internal void Send(byte Data)
        {
            byte[] buffer = new byte[1];
            buffer[0] = Data;
            m_commPort.Write(buffer, 0, 1);
        }
        internal void Send(byte[] Data)
        {
            m_commPort.Write(Data, 0, Data.Length);
        }
		internal int Port
		{
            get
            {
                return m_port;
            }
			set
			{
				m_port = value;
			}
		}
		internal int BaudRate
		{
            get
            {
                return m_baud;
            }
			set
			{
				m_baud = value;
			}
		}
        internal void m_commPort_DataReceived(object source, SerialDataReceivedEventArgs eargs)
        {
        

            //read all available bytes
            string sentence = m_commPort.ReadLine();

            ////get a byte array, code left here as an example
            //int index = 0;
            //byte[] buffer = new byte[sentence.Length];
            //foreach (char chr in sentence.ToCharArray())
            //{
            //    buffer[index] = (byte)chr;
            //    index++;
            //}
            //we already know it ends with a new line (m_commPort.ReadLine()) so check the start
            if (sentence.Length > 0 && sentence.StartsWith(NMEA_START))
            {
                //raise an event or buffer it in a collection
                if (OnRxSentence != null)
                {
                    OnRxSentence(this, new OnRxSentenceEventArgs(sentence + "\n"));
                }

            }
		}


        public bool Online
        {
            get
            {
                if (m_commPort == null)
                {
                    return false;
                }
                else
                {
                    return m_commPort.IsOpen;
                }
            }
        }
        // Public IDisposable.Dispose implementation - calls the internal helper,
        public void Dispose()
        {
            Dispose(true);
        }
        private void Dispose(bool disposing)
        {
            if (!disposed && disposing && m_commPort != null && m_commPort.IsOpen)
            {
                m_commPort.Close();

                // Keep us from calling resetting or closing multiple times
                disposed = true;
            }
        }

        //
        // Event definitions etc.
        //
        //
        public event OnRxSentenceEventHandler OnRxSentence;
        /// <summary>
        /// Delegate for the OnRxSentence event.
        /// </summary>
        public delegate void OnRxSentenceEventHandler(object DeviceObject, OnRxSentenceEventArgs SentenceArguments);
        //use the following code to raise the event
        //
        //		if (OnRxSentence != null)
        //		{
        //			OnRxSentence(this, new OnRxSentenceEventArgs(<string>));
        //		}

    }
    /// <summary>
    /// This class contains the Event Arguments for the OnRxSentence event.
    /// </summary>
    public class OnRxSentenceEventArgs : EventArgs
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        public OnRxSentenceEventArgs(string rxSentence)
        {
            m_rxSentence = rxSentence;
        }
        private string m_rxSentence;

        /// <summary>
        /// Returns the received Sentence as a string.
        /// </summary>
        public string RxSentence
        {
            get
            {
                return m_rxSentence;
            }
        }
    }
}
